package org.rajawali3d.view;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.graphics.Surface;
import ohos.agp.graphics.SurfaceOps;
import ohos.agp.render.opengl.EGLConfig;
import ohos.agp.render.opengl.GLES1X;
import ohos.app.Context;
import ohos.media.image.common.PixelFormat;
import ohos.opengl.GLSurfaceProvider;
import opengl.platform.ohos.Log;
import org.rajawali3d.renderer.ISurfaceRenderer;
import org.rajawali3d.util.Capabilities;
import org.rajawali3d.util.egl.RajawaliEGLConfigChooser;

/**
 * Rajawali version of a {@link GLSurfaceProvider}. If you plan on using Rajawali with a {@link GLSurfaceProvider},
 * it is imperative that you extend this class or life cycle events may not function as you expect.
 *
 * @author Jared Woolston (jwoolston@tenkiv.com)
 */
public class SurfaceView extends GLSurfaceProvider implements ISurface {

    protected RendererDelegate mRendererDelegate;

    protected double mFrameRate = 60.0;
    protected int mRenderMode = ISurface.RENDERMODE_WHEN_DIRTY;
    protected ANTI_ALIASING_CONFIG mAntiAliasingConfig = ANTI_ALIASING_CONFIG.NONE;
    protected boolean mIsTransparent = false;
    protected int mBitsRed = 5;
    protected int mBitsGreen = 6;
    protected int mBitsBlue = 5;
    protected int mBitsAlpha = 0;
    protected int mBitsDepth = 16;
    protected int mMultiSampleCount = 0;

    public SurfaceView(Context context) {
        super(context);
    }

    public SurfaceView(Context context, AttrSet attrs) {
        super(context, attrs);
        applyAttributes(context, attrs);
    }

    private void applyAttributes(Context context, AttrSet attrs) {
        if (attrs == null) return;


        if (attrs.getAttr("frameRate").isPresent()) {
            mFrameRate = attrs.getAttr("frameRate").get().getFloatValue();
        }
        if (attrs.getAttr("renderMode").isPresent()) {
            mRenderMode = attrs.getAttr("renderMode").get().getIntegerValue();
        }
        if (attrs.getAttr("antiAliasingType").isPresent()) {
            mAntiAliasingConfig = ANTI_ALIASING_CONFIG.fromInteger(attrs.getAttr("antiAliasingType").get().getIntegerValue());
        }
        if (attrs.getAttr("multiSampleCount").isPresent()) {
            mMultiSampleCount = attrs.getAttr("multiSampleCount").get().getIntegerValue();
        }
        if (attrs.getAttr("isTransparent").isPresent()) {
            mIsTransparent = attrs.getAttr("isTransparent").get().getBoolValue();
        }
        if (attrs.getAttr("bitsRed").isPresent()) {
            mBitsRed = attrs.getAttr("bitsRed").get().getIntegerValue();
        }
        if (attrs.getAttr("bitsGreen").isPresent()) {
            mBitsGreen = attrs.getAttr("bitsGreen").get().getIntegerValue();
        }
        if (attrs.getAttr("bitsBlue").isPresent()) {
            mBitsBlue = attrs.getAttr("bitsBlue").get().getIntegerValue();
        }
        if (attrs.getAttr("bitsAlpha").isPresent()) {
            mBitsAlpha = attrs.getAttr("bitsAlpha").get().getIntegerValue();
        }
        if (attrs.getAttr("bitsDepth").isPresent()) {
            mBitsDepth = attrs.getAttr("bitsDepth").get().getIntegerValue();
        }

    }

    private void initialize() {
        final int glesMajorVersion = Capabilities.getGLESMajorVersion();
//        int glesMajorVersion = 3;
        setEGLContextClientVersion(glesMajorVersion);

        if (mIsTransparent) {
            setEGLConfigChooser(new RajawaliEGLConfigChooser(glesMajorVersion, mAntiAliasingConfig, mMultiSampleCount,
                    8, 8, 8, 8, mBitsDepth));

            //getHolder().setFormat(PixelFormat.TRANSLUCENT);
            SurfaceOps ops = getSurfaceOps().get();
            ops.setFormat(PixelFormat.ARGB_8888.getValue());
            pinToZTop(true);
        } else {
            setEGLConfigChooser(new RajawaliEGLConfigChooser(glesMajorVersion, mAntiAliasingConfig, mMultiSampleCount,
                    mBitsRed, mBitsGreen, mBitsBlue, mBitsAlpha, mBitsDepth));
//            setEGLConfigChooser(mBitsRed, mBitsGreen, mBitsBlue, mBitsAlpha, mBitsDepth,0);
//            getHolder().setFormat(PixelFormat.RGBA_8888);
            SurfaceOps ops = getSurfaceOps().get();
            ops.setFormat(PixelFormat.ARGB_8888.getValue());
            pinToZTop(false);
        }
    }


    @Override
    public void onPause() {
        super.onPause();
        if (mRendererDelegate != null) {
            mRendererDelegate.mRenderer.onPause();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        if (mRendererDelegate != null) {
            mRendererDelegate.mRenderer.onResume();
        }
    }

    @Override
    public void setVisibility(int visibility) {
        if (visibility == HIDE || visibility == INVISIBLE) {
            onPause();
        } else {
            onResume();
        }
        super.setVisibility(visibility);
    }

    @Override
    public void onComponentBoundToWindow(Component component) {
        super.onComponentBoundToWindow(component);

        onResume();

    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
        try {
            mRendererDelegate.mRenderer.onRenderSurfaceDestroyed(null);
        } catch (NullPointerException ignored) {
            // Don't care, activity is terminating.
        }
        super.onComponentUnboundFromWindow(component);
    }

    @Override
    public void setFrameRate(double rate) {
        mFrameRate = rate;
        if (mRendererDelegate != null) {
            mRendererDelegate.mRenderer.setFrameRate(rate);
        }
    }

    @Override
    public int getRenderMode() {
        if (mRendererDelegate != null) {
            return super.getRenderMode();
        } else {
            return mRenderMode;
        }
    }

    @Override
    public void setRenderMode(int mode) {
        mRenderMode = mode;
        if (mRendererDelegate != null) {
            super.setRenderMode(mRenderMode);
        }
    }

    /**
     * Enable/Disable transparent background for this surface view.
     * Must be called before {@link #setSurfaceRenderer(ISurfaceRenderer)}.
     *
     * @param isTransparent {@code boolean} If true, this {@link SurfaceView} will be drawn transparent.
     */
    public void setTransparent(boolean isTransparent) {
        mIsTransparent = isTransparent;
    }

    @Override
    public void setAntiAliasingMode(ANTI_ALIASING_CONFIG config) {
        mAntiAliasingConfig = config;
    }

    @Override
    public void setSampleCount(int count) {
        mMultiSampleCount = count;
    }

    @Override
    public void setSurfaceRenderer(ISurfaceRenderer renderer) throws IllegalStateException {
        if (mRendererDelegate != null)
            throw new IllegalStateException("A renderer has already been set for this view.");
        initialize();
        final RendererDelegate delegate = new RendererDelegate(renderer, this);
        super.setRenderer(delegate);
        mRendererDelegate = delegate; // Done to make sure we dont publish a reference before its safe.
        // Render mode cant be set until the GL thread exists
        setRenderMode(mRenderMode);
        onPause(); // We want to halt the surface view until we are ready
    }

    public Surface getSurface() {
        return getSurfaceOps().get().getSurface();
    }

    @Override
    public void requestRenderUpdate() {
        requestRender();
    }

    /**
     * Delegate used to translate between {@link GLSurfaceProvider.Renderer} and {@link ISurfaceRenderer}.
     *
     * @author Jared Woolston (jwoolston@tenkiv.com)
     */
    private static class RendererDelegate implements Renderer {

        final SurfaceView mRajawaliSurfaceView; // The surface view to render on
        final ISurfaceRenderer mRenderer; // The renderer

        public RendererDelegate(ISurfaceRenderer renderer, SurfaceView surfaceView) {
            mRenderer = renderer;
            mRajawaliSurfaceView = surfaceView;
            mRenderer.setFrameRate(mRajawaliSurfaceView.mRenderMode == ISurface.RENDERMODE_WHEN_DIRTY ?
                    mRajawaliSurfaceView.mFrameRate : 60);
            mRenderer.setAntiAliasingMode(mRajawaliSurfaceView.mAntiAliasingConfig);
            mRenderer.setRenderSurface(mRajawaliSurfaceView);
        }

        @Override
        public void onSurfaceCreated(GLES1X gl, EGLConfig config) {
            mRenderer.onRenderSurfaceCreated(config, gl, -1, -1);
        }

        @Override
        public void onSurfaceChanged(GLES1X gl, int width, int height) {
            mRenderer.onRenderSurfaceSizeChanged(gl, width, height);
        }

        @Override
        public void onDrawFrame(GLES1X gl) {
            try {
                mRenderer.onRenderFrame(gl);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
